```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Sa-Token - 轻量级Java权限认证框架</title>
    <link href="https://cdn.staticfile.org/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
    <link href="https://cdn.staticfile.org/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
    <style>
        body {
            font-family: 'Noto Sans SC', 'Noto Serif SC', Tahoma, Arial, Roboto, "Droid Sans", "Helvetica Neue", "Droid Sans Fallback", "Hiragino Sans GB", Simsun, sans-serif;
            background-color: #f8fafc;
            color: #1e293b;
            line-height: 1.6;
        }
        .hero-gradient {
            background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%);
        }
        .code-block {
            background-color: #1e293b;
            color: #e2e8f0;
            border-radius: 0.5rem;
            padding: 1.5rem;
            position: relative;
        }
        .code-block pre {
            margin: 0;
            overflow-x: auto;
        }
        .feature-card:hover {
            transform: translateY(-5px);
            box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
        }
        .nav-link:hover {
            color: #4f46e5;
        }
        .nav-link.active {
            color: #4f46e5;
            border-bottom: 2px solid #4f46e5;
        }
        .animate-fade-in {
            animation: fadeIn 0.5s ease-in-out;
        }
        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(10px); }
            to { opacity: 1; transform: translateY(0); }
        }
    </style>
</head>
<body class="antialiased">
    <!-- 导航栏 -->
    <nav class="bg-white shadow-sm sticky top-0 z-50">
        <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
            <div class="flex justify-between h-16">
                <div class="flex items-center">
                    <div class="flex-shrink-0 flex items-center">
                        <span class="text-2xl font-bold text-indigo-600">Sa-Token</span>
                    </div>
                    <div class="hidden sm:ml-6 sm:flex sm:space-x-8">
                        <a href="#intro" class="nav-link inline-flex items-center px-1 pt-1 text-sm font-medium text-gray-900">介绍</a>
                        <a href="#env" class="nav-link inline-flex items-center px-1 pt-1 text-sm font-medium text-gray-500 hover:text-gray-700">环境搭建</a>
                        <a href="#auth" class="nav-link inline-flex items-center px-1 pt-1 text-sm font-medium text-gray-500 hover:text-gray-700">登录认证</a>
                        <a href="#permission" class="nav-link inline-flex items-center px-1 pt-1 text-sm font-medium text-gray-500 hover:text-gray-700">权限认证</a>
                        <a href="#kickout" class="nav-link inline-flex items-center px-1 pt-1 text-sm font-medium text-gray-500 hover:text-gray-700">踢人下线</a>
                    </div>
                </div>
                <div class="hidden sm:ml-6 sm:flex sm:items-center">
                    <a href="https://github.com/dromara/sa-token" target="_blank" class="text-gray-500 hover:text-indigo-600">
                        <span class="sr-only">GitHub</span>
                        <i class="fab fa-github text-xl"></i>
                    </a>
                </div>
            </div>
        </div>
    </nav>

    <!-- Hero 区域 -->
    <div class="hero-gradient text-white">
        <div class="max-w-7xl mx-auto py-16 px-4 sm:py-24 sm:px-6 lg:px-8">
            <div class="text-center animate-fade-in">
                <h1 class="text-4xl font-extrabold tracking-tight sm:text-5xl lg:text-6xl">
                    Sa-Token
                </h1>
                <p class="mt-6 max-w-2xl mx-auto text-xl">
                    一个轻量级 Java 权限认证框架，解决登录认证、权限认证、Session会话等一系列权限相关问题
                </p>
                <div class="mt-10">
                    <div class="inline-flex rounded-md shadow">
                        <a href="#env" class="inline-flex items-center justify-center px-5 py-3 border border-transparent text-base font-medium rounded-md text-indigo-600 bg-white hover:bg-indigo-50">
                            快速开始
                        </a>
                    </div>
                    <div class="ml-3 inline-flex">
                        <a href="https://github.com/dromara/sa-token" target="_blank" class="inline-flex items-center justify-center px-5 py-3 border border-transparent text-base font-medium rounded-md text-indigo-100 bg-indigo-600 bg-opacity-60 hover:bg-opacity-70">
                            <i class="fab fa-github mr-2"></i> GitHub
                        </a>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- 主要内容区 -->
    <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
        <!-- 特性概述 -->
        <div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-16">
            <div class="feature-card bg-white p-6 rounded-lg shadow-md transition-all duration-300">
                <div class="flex items-center mb-4">
                    <div class="flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-md bg-indigo-100 text-indigo-600">
                        <i class="fas fa-sign-in-alt text-xl"></i>
                    </div>
                    <h3 class="ml-4 text-lg font-medium text-gray-900">登录认证</h3>
                </div>
                <p class="text-gray-600">
                    简单易用的登录认证API，一行代码完成登录校验，支持同端互斥登录、多端登录等场景。
                </p>
            </div>
            <div class="feature-card bg-white p-6 rounded-lg shadow-md transition-all duration-300">
                <div class="flex items-center mb-4">
                    <div class="flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-md bg-purple-100 text-purple-600">
                        <i class="fas fa-user-shield text-xl"></i>
                    </div>
                    <h3 class="ml-4 text-lg font-medium text-gray-900">权限认证</h3>
                </div>
                <p class="text-gray-600">
                    灵活强大的权限管理，支持角色验证、权限通配符、按钮级权限控制，满足各种复杂权限场景。
                </p>
            </div>
            <div class="feature-card bg-white p-6 rounded-lg shadow-md transition-all duration-300">
                <div class="flex items-center mb-4">
                    <div class="flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-md bg-blue-100 text-blue-600">
                        <i class="fas fa-users-slash text-xl"></i>
                    </div>
                    <h3 class="ml-4 text-lg font-medium text-gray-900">会话管理</h3>
                </div>
                <p class="text-gray-600">
                    完善的会话管理功能，支持踢人下线、账号封禁、会话查询等功能，保障系统安全。
                </p>
            </div>
        </div>

        <!-- Sa-Token 介绍 -->
        <div id="intro" class="mb-16">
            <h2 class="text-3xl font-bold text-gray-900 mb-6 border-b pb-2">Sa-Token 介绍</h2>
            <div class="bg-white rounded-lg shadow-md p-6">
                <p class="text-gray-700 mb-4">
                    <strong>Sa-Token</strong> 是一个轻量级 Java 权限认证框架，主要解决：<span class="bg-indigo-100 text-indigo-800 px-2 py-1 rounded-md">登录认证</span>、<span class="bg-indigo-100 text-indigo-800 px-2 py-1 rounded-md">权限认证</span>、<span class="bg-indigo-100 text-indigo-800 px-2 py-1 rounded-md">Session会话</span>、<span class="bg-indigo-100 text-indigo-800 px-2 py-1 rounded-md">单点登录</span>、<span class="bg-indigo-100 text-indigo-800 px-2 py-1 rounded-md">OAuth2.0</span>、<span class="bg-indigo-100 text-indigo-800 px-2 py-1 rounded-md">微服务网关鉴权</span> 等一系列权限相关问题。
                </p>
                
                <p class="text-gray-700 mb-6">
                    Sa-Token 的 API 设计非常简单，以登录认证为例：
                </p>
                
                <div class="code-block mb-6">
                    <pre><code class="language-java">// 在登录时写入当前会话的账号id
StpUtil.login(10001);

// 然后在需要校验登录处调用以下方法：
// 如果当前会话未登录，这句代码会抛出 `NotLoginException` 异常
StpUtil.checkLogin();</code></pre>
                </div>
                
                <p class="text-gray-700 mb-6">
                    至此，我们已经借助 Sa-Token 完成登录认证！
                </p>
                
                <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
                    <div class="code-block">
                        <div class="flex justify-between items-center mb-2">
                            <span class="text-gray-400 text-sm">权限认证示例</span>
                        </div>
                        <pre><code class="language-java">@SaCheckPermission("user:add")
@RequestMapping("/user/insert")
public String insert(SysUser user) {
    // ... 
    return "用户增加";
}</code></pre>
                    </div>
                    
                    <div class="code-block">
                        <div class="flex justify-between items-center mb-2">
                            <span class="text-gray-400 text-sm">踢人下线示例</span>
                        </div>
                        <pre><code class="language-java">// 将账号id为 10001 的会话踢下线 
StpUtil.kickout(10001);</code></pre>
                    </div>
                </div>
                
                <div class="mt-6 code-block">
                    <div class="flex justify-between items-center mb-2">
                        <span class="text-gray-400 text-sm">常用API一览</span>
                    </div>
                    <pre><code class="language-java">StpUtil.login(10001);    // 标记当前会话登录的账号id
StpUtil.getLoginId();    // 获取当前会话登录的账号id
StpUtil.isLogin();       // 获取当前会话是否已经登录
StpUtil.logout();        // 当前会话注销登录
StpUtil.kickout(10001);  // 将账号为10001的会话踢下线
StpUtil.hasRole("super-admin");     // 查询当前账号是否含有指定角色
StpUtil.hasPermission("user:add");  // 查询当前账号是否含有指定权限
StpUtil.getSession();    // 获取当前账号id的Session
StpUtil.login(10001, "PC");  // 指定设备标识登录
StpUtil.kickout(10001, "PC"); // 指定账号指定设备标识踢下线
StpUtil.openSafe(120);    // 开启二级认证，有效期120秒 
StpUtil.checkSafe();     // 校验是否处于二级认证有效期内
StpUtil.switchTo(10044); // 临时切换为其它账号</code></pre>
                </div>
            </div>
        </div>

        <!-- 环境搭建 -->
        <div id="env" class="mb-16">
            <h2 class="text-3xl font-bold text-gray-900 mb-6 border-b pb-2">环境搭建</h2>
            <div class="bg-white rounded-lg shadow-md p-6">
                <div class="mb-6">
                    <h3 class="text-xl font-semibold text-gray-800 mb-3">1. 引入依赖</h3>
                    <p class="text-gray-700 mb-4">
                        在项目中直接通过 <code class="bg-gray-100 px-1 py-0.5 rounded">pom.xml</code> 引入 Sa-Token 的依赖即可：
                    </p>
                    <div class="code-block">
                        <pre><code class="language-xml">&lt;dependency&gt;
    &lt;groupId&gt;cn.dev33&lt;/groupId&gt;
    &lt;artifactId&gt;sa-token-spring-boot-starter&lt;/artifactId&gt;
    &lt;version&gt;1.29.0&lt;/version&gt;
&lt;/dependency&gt;</code></pre>
                    </div>
                </div>
                
                <div class="mb-6">
                    <h3 class="text-xl font-semibold text-gray-800 mb-3">2. yml配置</h3>
                    <p class="text-gray-700 mb-4">
                        你可以<strong>零配置启动项目</strong>，但同时你也可以在<code class="bg-gray-100 px-1 py-0.5 rounded">application.yml</code>中增加如下配置，定制性使用框架：
                    </p>
                    <div class="code-block">
                        <pre><code class="language-yaml">server:
    # 端口
    port: 8081

# Sa-Token配置
sa-token: 
    # token名称 (同时也是cookie名称)
    token-name: satoken
    # token有效期，单位s 默认30天, -1代表永不过期 
    timeout: 2592000
    # token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
    activity-timeout: -1
    # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) 
    is-concurrent: true
    # 在多人登录同一账号时，是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) 
    is-share: false
    # token风格
    token-style: uuid
    # 是否输出操作日志 
    is-log: false</code></pre>
                    </div>
                </div>
                
                <div>
                    <h3 class="text-xl font-semibold text-gray-800 mb-3">3. 创建Controller</h3>
                    <div class="code-block">
                        <pre><code class="language-java">@RestController
@RequestMapping("/user/")
public class UserController {

    // 测试登录，浏览器访问： http://localhost:8081/user/doLogin?username=zhang&password=123456
    @RequestMapping("doLogin")
    public String doLogin(String username, String password) {
        // 此处仅作模拟示例，真实项目需要从数据库中查询数据进行比对 
        if("zhang".equals(username) && "123456".equals(password)) {
            StpUtil.login(10001);
            return "登录成功";
        }
        return "登录失败";
    }

    // 查询登录状态，浏览器访问： http://localhost:8081/user/isLogin
    @RequestMapping("isLogin")
    public String isLogin() {
        return "当前会话是否登录：" + StpUtil.isLogin();
    }
}</code></pre>
                    </div>
                </div>
            </div>
        </div>

        <!-- 登录认证 -->
        <div id="auth" class="mb-16">
            <h2 class="text-3xl font-bold text-gray-900 mb-6 border-b pb-2">登录认证</h2>
            <div class="bg-white rounded-lg shadow-md p-6">
                <p class="text-gray-700 mb-6">
                    所谓登录认证，说白了就是限制某些API接口必须登录后才能访问（例：查询我的账号资料）<br>
                    那么如何判断一个会话是否登录？框架会在登录成功后给你做个标记，每次登录认证时校验这个标记，有标记者视为已登录，无标记者视为未登录！
                </p>
                
                <div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
                    <div>
                        <h3 class="text-xl font-semibold text-gray-800 mb-3">登录与注销</h3>
                        <div class="code-block">
                            <pre><code class="language-java">// 标记当前会话登录的账号id 
StpUtil.login(Object id);     

// 当前会话注销登录
StpUtil.logout();

// 获取当前会话是否已经登录
StpUtil.isLogin();

// 检验当前会话是否已经登录
StpUtil.checkLogin()</code></pre>
                        </div>
                    </div>
                    
                    <div>
                        <h3 class="text-xl font-semibold text-gray-800 mb-3">会话查询</h3>
                        <div class="code-block">
                            <pre><code class="language-java">// 获取当前会话账号id
StpUtil.getLoginId();

// 类似查询API还有：
StpUtil.getLoginIdAsString();
StpUtil.getLoginIdAsInt();
StpUtil.getLoginIdAsLong();

// 未登录时返回默认值
StpUtil.getLoginIdDefaultNull();
StpUtil.getLoginId(T defaultValue);</code></pre>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <!-- 权限认证 -->
        <div id="permission" class="mb-16">
            <h2 class="text-3xl font-bold text-gray-900 mb-6 border-b pb-2">权限认证</h2>
            <div class="bg-white rounded-lg shadow-md p-6">
                <p class="text-gray-700 mb-6">
                    所谓权限认证，认证的核心就是一个账号是否拥有一个权限码<br>
                    有，就让你通过。没有？那么禁止访问!
                </p>
                
                <p class="text-gray-700 mb-6">
                    再往底了说，就是每个账号都会拥有一个权限码集合，我来校验这个集合中是否包含指定的权限码<br>
                    例如：当前账号拥有权限码集合：<code class="bg-gray-100 px-1 py-0.5 rounded">["user-add", "user-delete", "user-get"]</code>，这时候我来校验权限 <code class="bg-gray-100 px-1 py-0.5 rounded">"user-update"</code>，则其结果就是：<strong>验证失败，禁止访问</strong>
                </p>
                
                <div class="mb-6">
                    <h3 class="text-xl font-semibold text-gray-800 mb-3">获取权限集合</h3>
                    <p class="text-gray-700 mb-4">
                        你需要新建一个类，实现<code class="bg-gray-100 px-1 py-0.5 rounded">StpInterface</code>接口：
                    </p>
                    <div class="code-block">
                        <pre><code class="language-java">@Component
public class StpInterfaceImpl implements StpInterface {

    // 返回一个账号所拥有的权限码集合 
    @Override
    public List&lt;String&gt; getPermissionList(Object loginId, String loginType) {
        List&lt;String&gt; list = new ArrayList&lt;String&gt;();    
        list.add("101");
        list.add("user-add");
        list.add("user-delete");
        list.add("user-update");
        list.add("user-get");
        list.add("article-get");
        return list;
    }

    // 返回一个账号所拥有的角色标识集合
    @Override
    public List&lt;String&gt; getRoleList(Object loginId, String loginType) {
        List&lt;String&gt; list = new ArrayList&lt;String&gt;();    
        list.add("admin");
        list.add("super-admin");
        return list;
    }
}</code></pre>
                    </div>
                </div>
                
                <div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
                    <div>
                        <h3 class="text-xl font-semibold text-gray-800 mb-3">权限校验</h3>
                        <div class="code-block">
                            <pre><code class="language-java">// 判断当前账号是否含有指定权限
StpUtil.hasPermission("user-update");        

// 校验当前账号是否含有指定权限
StpUtil.checkPermission("user-update");        

// 多个权限校验
StpUtil.checkPermissionAnd("user-update", "user-delete");        
StpUtil.checkPermissionOr("user-update", "user-delete");</code></pre>
                        </div>
                    </div>
                    
                    <div>
                        <h3 class="text-xl font-semibold text-gray-800 mb-3">角色校验</h3>
                        <div class="code-block">
                            <pre><code class="language-java">// 判断当前账号是否拥有指定角色
StpUtil.hasRole("super-admin");        

// 校验当前账号是否含有指定角色标识
StpUtil.checkRole("super-admin");        

// 多个角色校验
StpUtil.checkRoleAnd("super-admin", "shop-admin");        
StpUtil.checkRoleOr("super-admin", "shop-admin");</code></pre>
                        </div>
                    </div>
                </div>
                
                <div class="mb-6">
                    <h3 class="text-xl font-semibold text-gray-800 mb-3">权限通配符</h3>
                    <p class="text-gray-700 mb-4">
                        Sa-Token允许你根据通配符指定泛权限，例如当一个账号拥有<code class="bg-gray-100 px-1 py-0.5 rounded">user*</code>的权限时，<code class="bg-gray-100 px-1 py-0.5 rounded">user-add</code>、<code class="bg-gray-100 px-1 py-0.5 rounded">user-delete</code>、<code class="bg-gray-100 px-1 py-0.5 rounded">user-update</code>都将匹配通过
                    </p>
                    <div class="code-block">
                        <pre><code class="language-java">// 当拥有 user* 权限时
StpUtil.hasPermission("user-add");        // true
StpUtil.hasPermission("user-update");     // true
StpUtil.hasPermission("art-add");         // false

// 上帝权限：当一个账号拥有 "*" 权限时
// 可以验证通过任何权限码</code></pre>
                    </div>
                </div>
                
                <div>
                    <h3 class="text-xl font-semibold text-gray-800 mb-3">如何把权限精确搭到按钮级</h3>
                    <p class="text-gray-700 mb-4">
                        权限精确到按钮级的意思就是指：<strong>权限范围可以控制到页面上的每一个按钮是否显示</strong>
                    </p>
                    <p class="text-gray-700 mb-4">
                        思路：
                    </p>
                    <ol class="list-decimal list-inside text-gray-700 mb-4 space-y-2">
                        <li>在登录时，把当前账号拥有的所有权限码一次性返回给前端</li>
                        <li>前端将权限码集合保存在<code class="bg-gray-100 px-1 py-0.5 rounded">localStorage</code>或其它全局状态管理对象中</li>
                        <li>在需要权限控制的按钮上，使用js进行逻辑判断</li>
                    </ol>
                    <div class="code-block">
                        <div class="flex justify-between items-center mb-2">
                            <span class="text-gray-400 text-sm">Vue示例</span>
                        </div>
                        <pre><code class="language-html">&lt;button v-if="arr.indexOf('user:delete') > -1"&gt;
    删除按钮
&lt;/button&gt;</code></pre>
                    </div>
                </div>
            </div>
        </div>

        <!-- 踢人下线 -->
        <div id="kickout">
            <h2 class="text-3xl font-bold text-gray-900 mb-6 border-b pb-2">踢人下线</h2>
            <div class="bg-white rounded-lg shadow-md p-6">
                <div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
                    <div>
                        <h3 class="text-xl font-semibold text-gray-800 mb-3">强制注销</h3>
                        <div class="code-block">
                            <pre><code class="language-java">StpUtil.logout(10001);                    // 强制指定账号注销下线 
StpUtil.logout(10001, "PC");              // 强制指定账号指定端注销下线 
StpUtil.logoutByTokenValue("token");      // 强制指定 Token 注销下线</code></pre>
                        </div>
                    </div>
                    
                    <div>
                        <h3 class="text-xl font-semibold text-gray-800 mb-3">踢人下线</h3>
                        <div class="code-block">
                            <pre><code class="language-java">StpUtil.kickout(10001);                    // 将指定账号踢下线 
StpUtil.kickout(10001, "PC");              // 将指定账号指定端踢下线
StpUtil.kickoutByTokenValue("token");      // 将指定 Token 踢下线</code></pre>
                        </div>
                    </div>
                </div>
                
                <div class="mb-6">
                    <h3 class="text-xl font-semibold text-gray-800 mb-3">强制注销 和 踢人下线 的区别</h3>
                    <ul class="list-disc list-inside text-gray-700 space-y-2">
                        <li><strong>强制注销</strong>等价于对方主动调用了注销方法，再次访问会提示：Token无效。</li>
                        <li><strong>踢人下线</strong>不会清除Token信息，而是将其打上特定标记，再次访问会提示：Token已被踢下线。</li>
                    </ul>
                </div>
                
                <div>
                    <h3 class="text-xl font-semibold text-gray-800 mb-3">账号封禁</h3>
                    <p class="text-gray-700 mb-4">
                        对于违规账号，有时候我们仅仅将其踢下线还是远远不够的，我们还需要对其进行<strong>账号封禁</strong>防止其再次登录
                    </p>
                    <div class="code-block">
                        <pre><code class="language-java">// 封禁指定账号 
StpUtil.disable(10001, 86400); 

// 获取指定账号是否已被封禁
StpUtil.isDisable(10001); 

// 获取指定账号剩余封禁时间
StpUtil.getDisableTime(10001); 

// 解除封禁
StpUtil.untieDisable(10001);</code></pre>
                    </div>
                    <div class="mt-4 p-4 bg-yellow-50 border-l-4 border-yellow-400">
                        <div class="flex">
                            <div class="flex-shrink-0">
                                <i class="fas fa-exclamation-triangle text-yellow-400"></i>
                            </div>
                            <div class="ml-3">
                                <p class="text-sm text-yellow-700">
                                    对于正在登录的账号，对其账号封禁时并不会使其立刻注销。如果需要将其封禁后立即掉线，可采取<strong>先踢再封禁</strong>的策略。
                                </p>
                            </div>
                        </div>
                    </div>
                    <div class="code-block mt-4">
                        <pre><code class="language-java">// 先踢下线
StpUtil.kickout(10001); 
// 再封禁账号
StpUtil.disable(10001, 86400);</code></pre>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/mermaid@latest/dist/mermaid.min.js"></script>
    <script>
        mermaid.initialize({
            startOnLoad: true,
            theme: 'default',
            flowchart: {
                useMaxWidth: true,
                htmlLabels: true,
                curve: 'basis'
            }
        });
        
        // 平滑滚动
        document.querySelectorAll('a[href^="#"]').forEach(anchor => {
            anchor.addEventListener('click', function (e) {
                e.preventDefault();
                document.querySelector(this.getAttribute('href')).scrollIntoView({
                    behavior: 'smooth'
                });
            });
        });
        
        // 导航栏高亮
        const sections = document.querySelectorAll('section[id]');
        window.addEventListener('scroll', () => {
            let current = '';
            sections.forEach(section => {
                const sectionTop = section.offsetTop;
                const sectionHeight = section.clientHeight;
                if (pageYOffset >= sectionTop - 300) {
                    current = section.getAttribute('id');
                }
            });
            
            document.querySelectorAll('.nav-link').forEach(link => {
                link.classList.remove('active');
                if (link.getAttribute('href') === `#${current}`) {
                    link.classList.add('active');
                }
            });
        });
    </script>
</body>
</html>
```